/*
 * Basterd Game Engine
 *
 * Copyright (C) 2011 by TEJO-UFC
 *
 * 		This file is part of the "Basterd Graphics Engine"
 * 		See the copyright notice in basterd.h for conditions of distribution and use.
 *
 * NOTE: This header contains THIS.
 */

#ifndef BASTERD_ENGINE_MUTEX_CLASS_H_
#define BASTERD_ENGINE_MUTEX_CLASS_H_

// standard libraries, in order
#include <cmath>
#include <cfloat>
#include <cstdlib>
#include <cstdio>
#include <cstdarg>
#include <ctime>
#include <cstring>
#include <string>
#include <limits>

// TODO check whether this is alright
#include <memory.h>

#if 0 // (BASTERD_PLATFORM == BASTERD_PLATFORM_WIN32) || (BASTERD_PLATFORM == BASTERD_PLATFORM_WIN64)
	#include <winsock2.h>
	#include <ws2tcpip.h>
	#include <iphlpapi.h>

	typedef sockaddr_in __socketAddress;
	typedef SOCKET      __socket;

#elif 1 // (BASTERD_PLATFORM == BASTERD_PLATFORM_LINUX) || (BASTERD_PLATFORM == BASTERD_PLATFORM_LINUX)
	#include <sys/types.h>
	#include <sys/socket.h>
	#include <netinet/in.h>
	#include <netdb.h>
	#include <arpa/inet.h>
    #include <fcntl.h>

	typedef sockaddr_in __socketAddress;
	typedef int         __socket;
#endif

// STL containers
#include <deque>
#include <list>
#include <map>
#include <string>
#include <set>
#include <vector>
#include <queue>

// more STL stuff
#include <algorithm>
#include <functional>
#include <limits>

// C++ stream IO
#include <fstream>
#include <iostream>
#include <iomanip>
#include <sstream>


// special type for mutex and shared library handles
#if 0 // (BASTERD_PLATFORM == BASTERD_PLATFORM_WIN32) || (BASTERD_PLATFORM == BASTERD_PLATFORM_WIN64)
	typedef HANDLE OSMutex;

	//
	struct HINSTANCE__;
	typedef HINSTANCE__* SharedLibraryPointer;
#else
	typedef pthread_mutex_t OSMutex;
	typedef void* SharedLibraryPointer;
#endif


namespace basterd
{
		/** @brief Implements the mutex-based approach to protect data shared by
		 *		multiple threads.
		 *  @remarks
		 *		Threads are waiting for mutexes when using shared data. This means that threads
		 *		tells the mutex they are wanting to access the data protected by the mutex. Thus,
		 *		If the mutex is unlocked, then the thread can proceed its processing and access
		 *		the protected data. Ohterwhise, it waits until the mutex is unlocked to proceed.
		 *  @par
		 *		Once a mutex has been locked, no other thread is allowed to lock the mutex.
		 *  	Only one thread at a time can get access to the mutex, and only the thread
		 *	    that has locked the mutex may use or manipulate the data which the mutex
		 *		protects. To unlock a mutex after its work is done, the thread calls unlock().
		 *
		 *	@see Thread, MutexLocker
		 */
		class Mutex
		{
		public:

			/** Constructor: internally creates the mutex
			 */
			Mutex(void);

			/** Destructor: internally destroys the mutex
			 *  @warning Avoid
			 */
			~Mutex(void);

			/** This method is called by threads wanting to lock this mutex.
			 *  @remarks This method will block the calling thread until the mutex is available.
			 * 			 It could be immediately, if no other thread has locked it.
			 */
			void lock(void);

			/**
			 * Tries to lock this mutex. If it is not possible, this method returns immediately false.
			 *
			 * @return True, if this mutex was locked successfully.
			 *         False, otherwise.
			 */
			bool tryLock(void);

			/** Unlocks a mutex, telling the blocked threads that data protected by this
			 *  mutex is available.
			 */
			void unlock(void);

		protected:

			/**
			 * Internal, OS-specific mutex data structure
			 */
			OSMutex _mutex;
		};


		/** @brief Utility class that assures that Mutexes are locked/unlocked properly while the locker object is alive.
		 *
		 *  @remarks
		 *		This utility class helps programmers when they are locking shared data in methods and functions.
		 *		Using this class is very simple:
		 *			- At the constructor, use the desired mutex as argument, so it will get locked;
		 *			- At the desconstructor, use given mutex is unlocked. Thus, you don't need to code unlocks in your code and won't forget
		 *			  to unlock the mutex. Have fun! :P
		 *
		 *  @note Remember that your mutex must be valid in the entire "life" of this locker,
		 *		  because this class uses a pointer internally to avoid the destruction of
		 *		  the mutex, so we won't see blue screens.
		 */
		class MutexLocker
		{
		public:

			/** Constructor. Just locks the mutex.
			 */
			MutexLocker( Mutex& mutex );

			/** Destructor: unlocks the mutex
			 */
			~MutexLocker(void);

		private:

			/** @brief Private copy-constructor
			 *
			 *  @remarks MutexLockers are not here to be passed by copy as argument nor
			 *			 to be explicitly copied.
			 */
			MutexLocker( const MutexLocker& locker );

			/** @brief Private copy assignment operator
			 *
			 *  @remarks MutexLockers are not here to be passed by copy as argument nor
			 *			 to be explicitly copied.
			 */
			MutexLocker& operator = ( const MutexLocker& locker );

			/** Mutex that is locked/unlocked internally
			 */
			Mutex& mutex;
		};

		/** @brief Utility class for assuring that a mutex gets properly unlocked after destruction.
		 *
		 *  @remarks
		 *		This utility class helps programmers when they are locking shared data in methods and functions.
		 *		However, differently from MutexLocker, it only unlocks the mutex. Typical usage usually depends
		 *		on a mutex to be locked or after a call to Mutex::tryLock() suceeds.
		 *
		 *		Using this class is very simple:
		 *			- At the constructor, use the desired mutex as argument;
		 *			- At the destructor, use given mutex is unlocked. Thus, you don't need to code unlocks in your code and won't forget
		 *			  to unlock the mutex. Have fun! :P
		 *
		 *		Here comes a code sample depicting typical usage:
		 *		@code
		 *		MyClass::myMethod(void)
		 *		{
		 *			// gets a mutex from any place
		 *			if( mutex.tryLock() )
		 *			{
		 *				// assures the mutex gets unlocked
		 *				MutexUnlocker mu( mutex );
		 *
		 *				// < here come data-critical code... >
		 *			}
		 *		}
		 *		@endcode
		 *
		 *  @note Remember that your mutex must be valid in the entire "life" of this locker, because this class uses
		 *        a pointer internally to avoid the destruction of the mutex, so we won't see these annoying blue screens.
		 */
		class MutexUnlocker
		{
		public:

			/** Constructor. Just locks the mutex.
			 */
			MutexUnlocker( Mutex& mutex );

			/** Destructor: unlocks the mutex
			 */
			~MutexUnlocker(void);

		private:

			/** @brief Private copy-constructor. Avoids copies.
			 */
			MutexUnlocker( const MutexUnlocker& locker );

			/** @brief Private copy assignment operator. Avoids copies.
			 */
			MutexUnlocker& operator = ( const MutexUnlocker& locker );

			/** Mutex that is locked/unlocked internally
			 */
			Mutex& mutex;
		};

		/** Utility macro used to make methods synchronized. This is how it works:
		 *	- creates a local static mutex;
		 *	- create a locker object for that mutex;
		 *
		 *  What it does:
		 *	- makes things easier :P ;
		 *	- when this macro is called in a function/method, it inserts "mutex-locking code"
		 *	  that controls multiple-thread access in the remaining function/method's code.
		 *
		 *  Typical use for a <em>non-recursive</em> function:
		 *	<pre>
		 *		void mySynhcronizedFunction()
		 *		{
		 *			// let's make this function synchronized
		 *			BASTERD_SYNCHRONIZED
		 *
		 *			// now we can access shared variables safely, like
		 *			// file streams, lists or node position, for example.
		 *			<<Dangerous code here>>
		 *		}
		 *	</pre>
		 */
		#define BASTERD_SYNCHRONIZED						\
			static basterd::Mutex localMutex;				\
			basterd::MutexLocker localLocker(localMutex);


		/// For ease use, we allow lazy users call BASTERD_SYNC
		#define BASTERD_SYNC BASTERD_SYNCHRONIZED

}

#endif /* BASTERD_ENGINE_MUTEX_CLASS_H_ */
